export { }
// 接口的兼容性  只要接口中包含的属性满足另一个接口  就是兼容的
interface Animal {
  name: string
  age: number
}
interface Person {
  name: string
  age: number
  gender: number
}

function getName(a: Animal): string {
  return a.name
}
let a: Animal = {
  name: '',
  age: 0,
}
getName(a)

let p: Person = {
  name: '',
  age: 1,
  gender: 0
}
getName(p) // Person中包含Animal 所以可以这样操作

// 基本属性类型的兼容性
let num: number | string
let str: string = ''
num = str

let num2 = {
  toString() { }
}
num2 = str
// 错误 str = num2

namespace e {
  // 类的兼容性
  class Animal {
    name: string
  }
  class Bird extends Animal {
    age: number
  }
  let a: Animal = {
    name: 'bl'
  };
  let b: Bird = {
    name: 'bl',
    age: 19
  };

  // 如果 两个类都是空的  可以互相赋值
  a = b
  // b = a // 如果添加了具体属性 子类中包含父类中没有的属性  则不能赋值
}

// 函数的兼容性
/**
 * 比较参数
 * 比较返回值
 */
type Func = (a: number, b: number) => void
let sum: Func
function f1(a: number, b: number): void {

}
sum = f1

function f2(a: number) {

}
sum = f2 // 参数少了也可以

function f3() {

}
sum = f2 // 没有参数也可以

function f4(a: number, b: number, c: number): void {

}
// 错误 sum = f4  多了不可以  因为定义一个函数  如果不传入参  那参数就是undefined  但是如果多传了  ts会认为第三个参数得类型不可控

type GetPerson = () => { name: string, age: number } // 这是类型的声明 并不是真正的箭头函数  箭头后边的大括号里的就是返回值的定义
let getPerson: GetPerson
function g1() {
  return { name: 'smd', age: 18 }
}
getPerson = g1
function g2() {
  return { name: 'smd', age: 18, spk: '123' }
}
getPerson = g2

function g3() {
  return { name: 'smd' }
}
// getPerson = g3 不可以  返回值必须大于规定的类型 因为取值后进行操作时可能会报错 


namespace c {
  /**
   * 返回值类型是协变的   参数类型是逆变的
   * 
   * 返回值类型可以传子类,参数可以传父类
   * 参数逆变父类 返回值协变子类
   */
  class Animal {

  }
  class Dog extends Animal {
    name: string = 'Dog'
  }
  class BlackDog extends Dog {
    public age: number = 10
  }
  class WhiteDog extends Dog {
    public home: string = 'bj'
  }
  let animal: Animal
  let dog: Dog
  let blackDog: BlackDog
  let whiteDog: WhiteDog
  type Callback = (dog: Dog) => Dog
  function exec(callback: Callback): void {
    // 错误 callback(animal)
    callback(dog)
    callback(blackDog)
    callback(whiteDog)
  }
  /**
   * tsconfig中
   *  "strictFunctionTypes": true // 函数的 协变与逆变   为true时 参数不能多传  为false时，不校验
   */
}

// 泛型的兼容
interface Empty<T> {

}
let x: Empty<string> = 'smd' // { data: string }
let y: Empty<number> = 123 // { data: number }
x = y // 当Empty中没有属性时可以，但如果存在属性后则不能互相赋值

namespace d {
  // 枚举的兼容性  数字和枚举是兼容的
  enum Colors { Red, Yellow }
  let c: Colors
  c = Colors.Red
  c = 1
  let n: number = 100
  n = c
  c = n
}


